﻿#include "FITKAcousticsVTKGraphObjectPart.h"
#include "FITKAcousticsVTKGraphActor.h"

// VTK
#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>
#include <vtkUnsignedCharArray.h>
#include <vtkCellData.h>

// Graph
#include "FITKAcousticsVTKCommons.h"
#include "FITKAcousticsVTKColorMapPartManager.h"
#include "FITKAcousticsVTKColorMap.h"
#include "FITKAcousticsVTKGraphObjectSelect.h"

 // Case
#include "FITK_Component/FITKAbaqusData/FITKDataCaseManager.h"
#include "FITK_Component/FITKAbaqusData/FITKDataCase.h"
#include "FITK_Component/FITKAbaqusData/FITKAbaqusData.h"

// App
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"

// Data
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEModel.h"
#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMeshPartVTK.h"
#include "FITK_Interface/FITKInterfaceModel/FITKUnstructuredMesh.h"
#include "FITK_Interface/FITKInterfaceMesh/FITKMeshFeatureVTK.h"
#include "FITK_Interface/FITKInterfaceModel/FITKComponentManager.h"

// Color assign
#include "FITK_Interface/FITKInterfacePhysics/FITKAbstractSection.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKAbstractMaterial.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKSectionAssign.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKMaterialAssign.h"

// Graph and filter
#include "FITK_Interface/FITKVTKAlgorithm/FITKHighOrderCellFilter.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKSurfaceFilter.h"

// Test
//@{
#include <vtkDataSetWriter.h>
//@}

namespace Exchange
{
    FITKAcousticsVTKGraphObjectPart::FITKAcousticsVTKGraphObjectPart(AbaqusData::FITKAbaqusPart* part)
        : FITKAcousticsVTKGraphObject3D(part)
    {
        // Return if the input is nullptr.
        if (!part)
        {
            return;
        }

        // Intiailize the polygon offset.
        double po = FITKAcousticsVTKCommons::s_polygonOffsetCAD;
        m_polygonOffset = FITKAcousticsVTKCommons::GetRandomPolygonOffset(po, po + 1.);

        // Initialize the color map with the part id.
        m_colorMap = FITKAcousticsVTKColorMapPartManager::getInstance()->getPartColorMap(part->getDataObjectID());

        // Create the highlight selector.
        m_highlightSelector = new FITKAcousticsVTKGraphObjectSelect;
        m_addinGraphObjList.push_back(m_highlightSelector);
        
        // Generate the part actor.
        generateGraph(part);

        // Save the data type.
        m_graphInfo.Type = FITKAcousticsVTKCommons::MeshGraph;

        // Set the layer need to be rendered.
        setRenderLayer(0, 2);

        // Change the mesh color.
        colorBySection(true);

        //单元添加section的id
        idBySection();
    }

    void FITKAcousticsVTKGraphObjectPart::update(bool forceUpdate)
    {
        Q_UNUSED(forceUpdate);

        // Update the visibility.
        updateVisibility();

        // Update the actor.
        if (m_fActor)
        {
            m_fActor->update();
        }
    }

    void FITKAcousticsVTKGraphObjectPart::updateVisibility()
    {
        // Get the runtime settings for visibility.
        bool showCAD = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_CAD, true);
        // bool showMesh = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_MESH, true);
        bool mainFlag = this->Superclass::getDataVisibility() && showCAD;

        // Update the visibility with the flags.
        //@{
        // Show or hide actors.
        setVisible(mainFlag);
        //@}
    }

    void FITKAcousticsVTKGraphObjectPart::setVisible(bool visibility)
    {
        // Show or hide vertex.
        if (m_fActor)
        {
            m_fActor->SetVisibility(visibility);
        }

        // The highlightor.
        if (m_highlightSelector)
        {
            m_highlightSelector->setVisible(visibility && getDataVisibility() && (m_isHighlighting || m_isAdvHighlighting));
        }

        // Save the visibility.
        m_globalVisibility = visibility;
    }

    void FITKAcousticsVTKGraphObjectPart::colorByDefault(bool forceUpdate)
    {
        // If the color mode is the same as current mode, return.
        if (m_colorMode == ColorMode::ColorDefault && !forceUpdate)
        {
            return;
        }

        // Check the mesh data object and the actor pointer.
        if (!m_fActor || !m_colorMap || !m_featureMesh)
        {
            return;
        }

        // Enable show color with scalar.
        //@{
        m_fActor->setScalarVisibility(true);
        m_fActor->setScalarModeToUseCellFieldData();
        //@}

        // Set all face to the default color.
        int nCells = m_meshData->getNumberOfCells();
        QList<int> indice;
        for (int i = 0; i < nCells; i++)
        {
            indice.push_back(i);
        }

        m_colorMap->setCellsColor(c_defaultArrName, indice, FITKAcousticsVTKCommons::s_meshFaceColor);

        // Update the data if neccessary.
        bool needUpdate = m_colorMap->needUpdate();
        if (needUpdate)
        {
            // Update mesh color.
            m_featureMesh->update();

            // Update the color map.
            m_colorMap->update();
        }

        // Switch to the array.
        m_fActor->selectScalarArray(c_defaultArrName);
        m_fActor->update();

        // Set the color mode value.
        m_colorMode = ColorMode::ColorDefault;
    }

    void FITKAcousticsVTKGraphObjectPart::colorByMaterial(bool forceUpdate)
    {
        // If the color mode is the same as current mode, return.
        if (m_colorMode == ColorMode::ColorMaterial && !forceUpdate)
        {
            return;
        }

        // Set the graph actors with the material's color.
        // Down cast data object.
        AbaqusData::FITKAbaqusPart* part = AbaqusData::FITKAbaqusPart::SafeDownCastFITKAbaqusPart(_dataObj);
        if (!part || !m_fActor || !m_colorMap || !m_featureMesh)
        {
            return;
        }

        // Get the FE-model data.
        Acoustics::FITKAcousticsDiscModel* discModel = FITKGLODATA->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel)
        {
            return;
        }

        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();

        // Get the section, assign and set manager, and also the model's color map.
        Interface::FITKAbstractSectionManager* secMgr = feModel->getSectionManager();
        Interface::FITKSectionAssignManager* assMgr = part->getSectionAssignManager();
        Interface::FITKComponentManager* setMgr = part->getComponentManager();

        if (!secMgr || !assMgr || !setMgr)
        {
            return;
        }

        // Enable show color with scalar.
        //@{
        m_fActor->setScalarVisibility(true);
        m_fActor->setScalarModeToUseCellFieldData();
        //@}

        // Filled color with none color first.
        //@{
        QList<int> indiceInit;
        int nCell = m_meshData->getNumberOfCells();
        for (int i = 0; i < nCell; i++)
        {
            indiceInit.push_back(i);
        }

        m_colorMap->setCellsColor(c_materialArrName, indiceInit, FITKAcousticsVTKCommons::s_meshFaceColor);
        //@}

        // Get all assigned sections.
        int nAssign = assMgr->getDataCount();
        for (int i = 0; i < nAssign; i++)
        {
            // Get assign.
            Interface::FITKSectionAssign* assign = assMgr->getDataByIndex(i);
            if (!assign)
            {
                continue;
            }

            // Get set.
            int setId = assign->getModelID();
            Interface::FITKAbstractModelComponent* set = setMgr->getDataByID(setId);
            if (!set)
            {
                continue;
            }

            // Convert to model set.
            Interface::FITKModelSet* modelSet = dynamic_cast<Interface::FITKModelSet*>(set);
            if (!modelSet)
            {
                continue;
            }

            // Get section.
            int secDataId = assign->getSectionID();
            Interface::FITKAbstractSection* sec = secMgr->getDataByID(secDataId);

            int matId = -1;
            bool hasValidSecAndMat = false;

            if (sec)
            {
                // The section ID.
                int secId = sec->getSectionID();
                if (secId > 0)
                {
                    secId--;
                }

                // Get material id.
                Interface::FITKAbstractMaterial* mat = sec->getMaterial();
                if (mat)
                {
                    hasValidSecAndMat = true;
                    matId = mat->getMaterialID();
                }

                if (matId > 0)
                {
                    matId--;
                }
            }

            // Get element set(s).
            QList<Interface::FITKModelSet*> sets;
            modelSet->getAbsoluteSet(sets, Interface::FITKModelEnum::FITKModelSetType::FMSElem);

            for (Interface::FITKModelSet* s : sets)
            {
                // Get element indice and the material color need to be set.
                QList<int> indice;
                getSetIds(s, indice);

                if (hasValidSecAndMat)
                {
                    QColor color = FITKAcousticsVTKCommons::GetColorByIndex(matId);
                    m_colorMap->setCellsColor(c_materialArrName, indice, color);
                }
                else
                {
                    // None section color.
                    m_colorMap->setCellsColor(c_materialArrName, indice, FITKAcousticsVTKCommons::s_meshFaceColor);
                }
            }
        }

        // Update the data if neccessary.
        bool needUpdate = m_colorMap->needUpdate();
        if (needUpdate)
        {
            // Update mesh color.
            m_featureMesh->update();

            // Update the color map.
            m_colorMap->update();
        }

        // Switch to the array.
        m_fActor->selectScalarArray(c_materialArrName);
        m_fActor->update();

        // Set the color mode value.
        m_colorMode = ColorMode::ColorMaterial;
    }

    void FITKAcousticsVTKGraphObjectPart::colorBySection(bool forceUpdate)
    {
        // If the color mode is the same as current mode, return.
        if (m_colorMode == ColorMode::ColorSection && !forceUpdate)
        {
            return;
        }

        // Set the graph actors with the section's color.
         // Get the part data object.
        AbaqusData::FITKAbaqusPart* part = AbaqusData::FITKAbaqusPart::SafeDownCastFITKAbaqusPart(_dataObj);
        if (!part || !m_fActor || !m_colorMap || !m_featureMesh)
        {
            return;
        }

        // Get the FE-model data.
        Acoustics::FITKAcousticsDiscModel* discModel = FITKGLODATA->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel)
        {
            return;
        }

        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();

        // Get the section, assign and set manager, and also the model's color map.
        Interface::FITKAbstractSectionManager* secMgr = feModel->getSectionManager();
        Interface::FITKSectionAssignManager* assMgr = part->getSectionAssignManager();
        Interface::FITKComponentManager* setMgr = part->getComponentManager();

        if (!secMgr || !assMgr || !setMgr)
        {
            return;
        }

        // Enable show color with scalar.
        //@{
        m_fActor->setScalarVisibility(true);
        m_fActor->setScalarModeToUseCellFieldData();
        //@}

        // Filled color with none color first.
        //@{
        QList<int> indiceInit;
        int nCell = m_meshData->getNumberOfCells();
        for (int i = 0; i < nCell; i++)
        {
            indiceInit.push_back(i);
        }

        m_colorMap->setCellsColor(c_sectionArrName, indiceInit, FITKAcousticsVTKCommons::s_meshFaceColor);
        //@}

        // Get all assigned sections.
        int nAssign = assMgr->getDataCount();
        for (int i = 0; i < nAssign; i++)
        {
            // Get assign.
            Interface::FITKSectionAssign* assign = assMgr->getDataByIndex(i);
            if (!assign)
            {
                continue;
            }

            // Get set.
            int setId = assign->getModelID();
            Interface::FITKAbstractModelComponent* set = setMgr->getDataByID(setId);

            // Convert to model set.
            Interface::FITKModelSet* modelSet = dynamic_cast<Interface::FITKModelSet*>(set);
            if (!modelSet)
            {
                continue;
            }

            // Get section.
            int secDataId = assign->getSectionID();
            Interface::FITKAbstractSection* sec = secMgr->getDataByID(secDataId);

            // The section ID.
            int secId = sec->getSectionID();
            if (secId > 0)
            {
                secId--;
            }

            // Get element set(s).
            QList<Interface::FITKModelSet*> sets;
            modelSet->getAbsoluteSet(sets, Interface::FITKModelEnum::FITKModelSetType::FMSElem);

            for (Interface::FITKModelSet* s : sets)
            {
                // Get element indice and the section color need to be set.
                QList<int> indice;
                getSetIds(s, indice);

                if (sec)
                {
                    QColor color = FITKAcousticsVTKCommons::GetColorByIndex(secId);
                    m_colorMap->setCellsColor(c_sectionArrName, indice, color);
                }
                else
                {
                    // None section color.
                    m_colorMap->setCellsColor(c_sectionArrName, indice, FITKAcousticsVTKCommons::s_meshFaceColor);
                }
            }
        }

        // Update the data if neccessary.
        bool needUpdate = m_colorMap->needUpdate();
        if (needUpdate)
        {
            // Update mesh color.
            m_featureMesh->update();

            // Update the color map.
            m_colorMap->update();
        }

        // Switch to the array.
        m_fActor->selectScalarArray(c_sectionArrName);
        m_fActor->update();

        // Set the color mode value.
        m_colorMode = ColorMode::ColorSection;
    }

    void FITKAcousticsVTKGraphObjectPart::idBySection()
    {
        Acoustics::FITKAcousticsDiscModel* discModel = FITKGLODATA->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (discModel == nullptr)
            return;
        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();
        if (feModel == nullptr)
            return;
        AbaqusData::FITKAbaqusPart* part = AbaqusData::FITKAbaqusPart::SafeDownCastFITKAbaqusPart(_dataObj);
        if (part == nullptr)
            return;
        Interface::FITKAbstractSectionManager* secMgr = feModel->getSectionManager();
        if (secMgr == nullptr)
            return;
        Interface::FITKSectionAssignManager* assMgr = part->getSectionAssignManager();
        if (assMgr == nullptr)
            return;
        Interface::FITKComponentManager* setMgr = part->getComponentManager();
        if (setMgr == nullptr)
            return;
        Interface::FITKAbaMeshPartVTK* mesh = part->getMesh();
        if (mesh == nullptr)
            return;
        vtkUnstructuredGrid* grid = mesh->getGrid();
        if (grid == nullptr)
            return;

        //设置单元sectionId默认值
        vtkSmartPointer<vtkUnsignedCharArray> sectionIdArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
        int cellNum = grid->GetNumberOfCells();
        sectionIdArray->SetNumberOfComponents(1);
        sectionIdArray->SetName("CellSectionIds");
        //分配数组空间
        int nTup = sectionIdArray->GetNumberOfTuples();
        if (cellNum != nTup) {
            sectionIdArray->SetNumberOfTuples(cellNum);
        }
        //数组数据初始化
        for (int i = 0; i < cellNum; i++){
            sectionIdArray->SetComponent(i, 0, -1);
        }
        grid->GetCellData()->AddArray(sectionIdArray);
        
        //存储具体单元的sectionId
        int nAssign = assMgr->getDataCount();
        for (int i = 0; i < nAssign; i++) {
            Interface::FITKSectionAssign* assign = assMgr->getDataByIndex(i);
            if (!assign) {
                continue;
            }

            int setId = assign->getModelID();
            Interface::FITKAbstractModelComponent* set = setMgr->getDataByID(setId);
            Interface::FITKModelSet* modelSet = dynamic_cast<Interface::FITKModelSet*>(set);
            if (!modelSet) {
                continue;
            }
            int secDataId = assign->getSectionID();
            Interface::FITKAbstractSection* sec = secMgr->getDataByID(secDataId);
            if(sec == nullptr)
                continue;

            //为单元添加sectionID
            QList<Interface::FITKModelSet*> sets;
            modelSet->getAbsoluteSet(sets, Interface::FITKModelEnum::FITKModelSetType::FMSElem);
            for (Interface::FITKModelSet* s : sets) {
                QList<int> indice;
                getSetIds(s, indice);
                for (int cellID : indice) {
                    sectionIdArray->SetComponent(cellID, 0, secDataId);
                }
            }
        }
    }

    void FITKAcousticsVTKGraphObjectPart::setTransparent(bool isOn)
    {
        // Get the opacity.
        double opa = isOn ? 1. - FITKAcousticsVTKCommons::s_defaultModelTransparency : 1.;

        for (vtkProp* prop : m_actorList)
        {
            vtkActor* actor = vtkActor::SafeDownCast(prop);
            if (actor)
            {
                actor->GetProperty()->SetOpacity(opa);
            }
        }
    }

    void FITKAcousticsVTKGraphObjectPart::highlight(FITKAcousticsVTKCommons::ShapeType type, QColor color)
    {
        // Show the actor and initialize the data.
        if (!m_highlightSelector)
        {
            return;
        }

        // Default highlight all elements.
        if (type == FITKAcousticsVTKCommons::ShapeType::ShapeTypeNone)
        {
            type = FITKAcousticsVTKCommons::ShapeType::MeshElement;
        }

        vtkDataSet* meshDataSet = getMesh(type);
        if (!meshDataSet)
        {
            return;
        }

        QVector<int> indice;
        for (int i = 0; i < meshDataSet->GetNumberOfCells(); i++)
        {
            indice.push_back(i);
        }

        // Check the color.
        if (!color.isValid())
        {
            color = Qt::red;
        }

        m_highlightSelector->setColor(color);
        m_highlightSelector->setSelectData(meshDataSet, indice, type);
        m_highlightSelector->setVisible(getDataVisibility());

        // Save the highlight flag.
        this->Superclass::highlight(type, color);
    }

    void FITKAcousticsVTKGraphObjectPart::disHighlight()
    {
        // Hide the actor only.
        if (m_highlightSelector)
        {
            m_highlightSelector->clearData();
            m_highlightSelector->setVisible(false);
        }

        // Save the highlight flag.
        this->Superclass::disHighlight();
    }

    void FITKAcousticsVTKGraphObjectPart::advanceHighlight(FITKAcousticsVTKCommons::ShapeType type, QVector<int> indice, QColor color)
    {
        // Show the actor and initialize the data.
        if (!m_highlightSelector || !m_meshData)
        {
            return;
        }

        if (indice.isEmpty())
        {
            return;
        }

        vtkDataSet* meshDataSet = getMesh(type);
        if (!meshDataSet)
        {
            return;
        }

        QVector<int> vtkIndice;

        // Get the model shape type.
        FITKAcousticsVTKCommons::ShapeMeshAbsEnum shapeEnum;
        switch (type)
        {
        case FITKAcousticsVTKCommons::MeshNode:
        {
            shapeEnum = FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_VERTEX;

            // Transfer the ids.
            for (const int & id : indice)
            {
                int vtkIndex = m_meshData->getNodeIndexByID(id);
                if (vtkIndex >= 0)
                {
                    vtkIndice.push_back(vtkIndex);
                }
            }

            break;
        }
        case FITKAcousticsVTKCommons::MeshElement:
        {
            shapeEnum = FITKAcousticsVTKCommons::ShapeMeshAbsEnum::STA_FACE;

            // Transfer the ids.
            for (const int & id : indice)
            {
                int vtkIndex = m_meshData->getEleIndexByID(id);
                if (vtkIndex >= 0)
                {
                    vtkIndice.push_back(vtkIndex);
                }
            }

            break;
        }
        default:
            return;
        }

        // Check the color.
        if (!color.isValid())
        {
            color = Qt::red;
        }

        m_highlightSelector->setColor(color);
        m_highlightSelector->setSelectData(meshDataSet, vtkIndice, type);
        m_highlightSelector->setVisible(getDataVisibility());

        // Save the highlight flag.
        this->Superclass::advanceHighlight(type, vtkIndice, color);
    }

    void FITKAcousticsVTKGraphObjectPart::disAdvanceHighlight()
    {
        // Clear data and hide the actor.
        if (m_highlightSelector)
        {
            m_highlightSelector->clearData();
            m_highlightSelector->setVisible(false);
        }

        // Save the highlight flag.
        this->Superclass::disAdvanceHighlight();
    }

    void FITKAcousticsVTKGraphObjectPart::setPickMode(FITKAcousticsVTKCommons::ShapePickMode mode)
    {
        if (!m_fActor)
        {
            return;
        }

        // Enable or disable pickablility.
        switch (mode)
        {
        case Exchange::FITKAcousticsVTKCommons::PickNode:
        case Exchange::FITKAcousticsVTKCommons::PickElement:
        case Exchange::FITKAcousticsVTKCommons::PickAll:
            m_fActor->SetPickable(true);
            break;
        default:
            m_fActor->SetPickable(false);
            break;
        }
    }

    int FITKAcousticsVTKGraphObjectPart::getShapeIdByVTKCellId(int vtkId, FITKAcousticsVTKCommons::ShapeMeshAbsEnum topAbsShapeType)
    {
        if (!m_meshData)
        {
            return -1;
        }

        // Get the surface filter.
        FITKSurfaceFilter* surfaceFilter = m_meshData->getMeshFeature()->getSurfaceFilter();
        if (!surfaceFilter)
        {
            return -1;
        }

        int id = -1;

        // Deal the mesh cell only.
        switch (topAbsShapeType)
        {
        case Exchange::FITKAcousticsVTKCommons::MT_Node:
        {
            // Get the node id in part mesh.
            int originPointIndex = surfaceFilter->getOriginPointIdBySurfacePointId(vtkId);
            if (originPointIndex != -1)
            {
                id = m_meshData->getNodeIDByIndex(originPointIndex);
            }

            break;
        }
        case Exchange::FITKAcousticsVTKCommons::MT_Element:
        {
            int faceIndex = -1;

            // Get the element id in part mesh.
            int orgCellIndex = -1;
            surfaceFilter->getSurfaceCellInfo(vtkId, orgCellIndex, faceIndex);
            if (orgCellIndex != -1)
            {
                id = m_meshData->getEleIDByIndex(orgCellIndex);
            }

            break;
        }
        default:
            break;
        }

        return id;
    }

    const QVector<int> FITKAcousticsVTKGraphObjectPart::getVTKCellIdsByShapeId(int shapeId, FITKAcousticsVTKCommons::ShapeMeshAbsEnum topAbsShapeType)
    {
        QVector<int> indice;

        if (!m_meshData)
        {
            return indice;
        }

        int vtkOrgId = -1;

        // Deal the mesh cell only.
        switch (topAbsShapeType)
        {
        case Exchange::FITKAcousticsVTKCommons::MT_Node:
            // Get the original node id of the point.
            vtkOrgId = m_meshData->getNodeIndexByID(shapeId);
            break;
        case Exchange::FITKAcousticsVTKCommons::MT_Element:
            // Get the original cell id of the element.
            vtkOrgId = m_meshData->getEleIndexByID(shapeId);
            break;
        default:
            break;
        }

        if (vtkOrgId != -1)
        {
            indice.push_back(vtkOrgId);
        }

        return indice;
    }

    void FITKAcousticsVTKGraphObjectPart::getSetIds(Interface::FITKModelSet* set, QList<int> & indice)
    {
        indice.clear();

        if (!set || !m_meshData)
        {
            return;
        }

        // Get real members.
        QList<int> members = set->getAbsoluteMember();

        // Get real indice.
        for (int& id : members)
        {
            int index = m_meshData->getEleIndexByID(id);
            if (index != -1)
            {
                indice.push_back(index);
            }
        }
    }

    void FITKAcousticsVTKGraphObjectPart::generateGraph(AbaqusData::FITKAbaqusPart* part)
    {
        // Get mesh data from the part data.
        m_meshData = part->getMesh();
        if (!m_meshData)
        {
            return;
        }

        // Get surface data for visualization.
        m_featureMesh = m_meshData->getMeshFeature();
        if (!m_featureMesh)
        {
            return;
        }

        // Update mesh data.
        m_featureMesh->update();

        // Get vtk surface data from the mesh data, and save the feature edge filter for simplified model.
        m_highOrderCellFilter = m_featureMesh->getHighOrderFilter();
        if (!m_highOrderCellFilter)
        {
            return;
        }

        // Create actor.
        m_fActor = FITKAcousticsVTKGraphActor::New();
        m_fActor->setGraphObject(this);
        m_fActor->setActorType(ActorType::SurfaceActor);
        m_fActor->SetPickable(false);
        m_fActor->SetVisibility(true);
        m_fActor->GetProperty()->SetRepresentation(2);
        m_fActor->GetProperty()->SetEdgeVisibility(true);
        m_fActor->GetProperty()->SetLineWidth(0.);
        m_fActor->setRelativeCoincidentTopologyPolygonOffsetParameters(m_polygonOffset);
        addActor(m_fActor);

        m_fActor->setInputConnection(m_highOrderCellFilter->GetOutputPort());

        // Initialize light properties.
        setLightPropertiesForSurface(m_fActor);
    }

    vtkDataSet* FITKAcousticsVTKGraphObjectPart::getMesh(FITKAcousticsVTKCommons::ShapeType type)
    {
        Q_UNUSED(type);

        // Get the source data set for the feature.
        if (!m_meshData)
        {
            return nullptr;
        }

        return m_meshData->getGrid();
    }

    bool FITKAcousticsVTKGraphObjectPart::test(QVariant & v)
    {
        QString filePath = v.toString();
        if (!m_fActor || filePath.isEmpty())
        {
            return false;
        }

        vtkDataSet* meshDataSet = m_fActor->getInputAsDataSet();
        if (!meshDataSet)
        {
            return false;
        }

        vtkSmartPointer<vtkDataSetWriter> writer = vtkSmartPointer<vtkDataSetWriter>::New();
        writer->SetInputData(meshDataSet);
        writer->SetFileName(filePath.toUtf8().data());
        writer->Update();

        return true;
    }
}   // namespace Exchange